home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / cl_parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  18.9 KB  |  812 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // cl_parse.c  -- parse a message received from the server
  21.  
  22. #include "client.h"
  23.  
  24. char *svc_strings[256] =
  25. {
  26.     "svc_bad",
  27.  
  28.     "svc_muzzleflash",
  29.     "svc_muzzlflash2",
  30.     "svc_temp_entity",
  31.     "svc_layout",
  32.     "svc_inventory",
  33.  
  34.     "svc_nop",
  35.     "svc_disconnect",
  36.     "svc_reconnect",
  37.     "svc_sound",
  38.     "svc_print",
  39.     "svc_stufftext",
  40.     "svc_serverdata",
  41.     "svc_configstring",
  42.     "svc_spawnbaseline",    
  43.     "svc_centerprint",
  44.     "svc_download",
  45.     "svc_playerinfo",
  46.     "svc_packetentities",
  47.     "svc_deltapacketentities",
  48.     "svc_frame"
  49. };
  50.  
  51. //=============================================================================
  52.  
  53. void CL_DownloadFileName(char *dest, int destlen, char *fn)
  54. {
  55.     if (strncmp(fn, "players", 7) == 0)
  56.         Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
  57.     else
  58.         Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
  59. }
  60.  
  61. /*
  62. ===============
  63. CL_CheckOrDownloadFile
  64.  
  65. Returns true if the file exists, otherwise it attempts
  66. to start a download from the server.
  67. ===============
  68. */
  69. qboolean    CL_CheckOrDownloadFile (char *filename)
  70. {
  71.     FILE *fp;
  72.     char    name[MAX_OSPATH];
  73.  
  74.     if (strstr (filename, ".."))
  75.     {
  76.         Com_Printf ("Refusing to download a path with ..\n");
  77.         return true;
  78.     }
  79.  
  80.     if (FS_LoadFile (filename, NULL) != -1)
  81.     {    // it exists, no need to download
  82.         return true;
  83.     }
  84.     return true; //fuck this shit!!
  85.     strcpy (cls.downloadname, filename);
  86.  
  87.     // download to a temp name, and only rename
  88.     // to the real name when done, so if interrupted
  89.     // a runt file wont be left
  90.     COM_StripExtension (cls.downloadname, cls.downloadtempname);
  91.     strcat (cls.downloadtempname, ".tmp");
  92.  
  93. //ZOID
  94.     // check to see if we already have a tmp for this file, if so, try to resume
  95.     // open the file if not opened yet
  96.     CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
  97.  
  98. //    FS_CreatePath (name);
  99.  
  100.     fp = fopen (name, "r+b");
  101.     if (fp) { // it exists
  102.         int len;
  103.         fseek(fp, 0, SEEK_END);
  104.         len = ftell(fp);
  105.  
  106.         cls.download = fp;
  107.  
  108.         // give the server an offset to start the download
  109.         Com_Printf ("Resuming %s\n", cls.downloadname);
  110.         MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  111.         MSG_WriteString (&cls.netchan.message,
  112.             va("download %s %i", cls.downloadname, len));
  113.     } else {
  114.         Com_Printf ("Downloading %s\n", cls.downloadname);
  115.         MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  116.         MSG_WriteString (&cls.netchan.message,
  117.             va("download %s", cls.downloadname));
  118.     }
  119.  
  120.     cls.downloadnumber++;
  121.  
  122.     return false;
  123. }
  124.  
  125. /*
  126. ===============
  127. CL_Download_f
  128.  
  129. Request a download from the server
  130. ===============
  131. */
  132. void    CL_Download_f (void)
  133. {
  134.     char filename[MAX_OSPATH];
  135.  
  136.     if (Cmd_Argc() != 2) {
  137.         Com_Printf("Usage: download <filename>\n");
  138.         return;
  139.     }
  140.  
  141.     Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
  142.  
  143.     if (strstr (filename, ".."))
  144.     {
  145.         Com_Printf ("Refusing to download a path with ..\n");
  146.         return;
  147.     }
  148.  
  149.     if (FS_LoadFile (filename, NULL) != -1)
  150.     {    // it exists, no need to download
  151.         Com_Printf("File already exists.\n");
  152.         return;
  153.     }
  154.  
  155.     strcpy (cls.downloadname, filename);
  156.     Com_Printf ("Downloading %s\n", cls.downloadname);
  157.  
  158.     // download to a temp name, and only rename
  159.     // to the real name when done, so if interrupted
  160.     // a runt file wont be left
  161.     COM_StripExtension (cls.downloadname, cls.downloadtempname);
  162.     strcat (cls.downloadtempname, ".tmp");
  163.  
  164.     MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  165.     MSG_WriteString (&cls.netchan.message,
  166.         va("download %s", cls.downloadname));
  167.  
  168.     cls.downloadnumber++;
  169. }
  170.  
  171. /*
  172. ======================
  173. CL_RegisterSounds
  174. ======================
  175. */
  176. void CL_RegisterSounds (void)
  177. {
  178.     int        i;
  179.  
  180.     S_BeginRegistration ();
  181.     CL_RegisterTEntSounds ();
  182.     for (i=1 ; i<MAX_SOUNDS ; i++)
  183.     {
  184.         if (!cl.configstrings[CS_SOUNDS+i][0])
  185.             break;
  186.         cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
  187.         Sys_SendKeyEvents ();    // pump message loop
  188.     }
  189.     S_EndRegistration ();
  190. }
  191.  
  192.  
  193. /*
  194. =====================
  195. CL_ParseDownload
  196.  
  197. A download message has been received from the server
  198. =====================
  199. */
  200. void CL_ParseDownload (void)
  201. {
  202.     int        size, percent;
  203.     char    name[MAX_OSPATH];
  204.     int        r;
  205.  
  206.     // read the data
  207.     size = MSG_ReadShort (&net_message);
  208.     percent = MSG_ReadByte (&net_message);
  209.     if (size == -1)
  210.     {
  211.         Com_Printf ("Server does not have this file.\n");
  212.         if (cls.download)
  213.         {
  214.             // if here, we tried to resume a file but the server said no
  215.             fclose (cls.download);
  216.             cls.download = NULL;
  217.         }
  218.         CL_RequestNextDownload ();
  219.         return;
  220.     }
  221.  
  222.     // open the file if not opened yet
  223.     if (!cls.download)
  224.     {
  225.         CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
  226.  
  227.         FS_CreatePath (name);
  228.  
  229.         cls.download = fopen (name, "wb");
  230.         if (!cls.download)
  231.         {
  232.             net_message.readcount += size;
  233.             Com_Printf ("Failed to open %s\n", cls.downloadtempname);
  234.             CL_RequestNextDownload ();
  235.             return;
  236.         }
  237.     }
  238.  
  239.     fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
  240.     net_message.readcount += size;
  241.  
  242.     if (percent != 100)
  243.     {
  244.         // request next block
  245. // change display routines by zoid
  246. #if 0
  247.         Com_Printf (".");
  248.         if (10*(percent/10) != cls.downloadpercent)
  249.         {
  250.             cls.downloadpercent = 10*(percent/10);
  251.             Com_Printf ("%i%%", cls.downloadpercent);
  252.         }
  253. #endif
  254.         cls.downloadpercent = percent;
  255.  
  256.         MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  257.         SZ_Print (&cls.netchan.message, "nextdl");
  258.     }
  259.     else
  260.     {
  261.         char    oldn[MAX_OSPATH];
  262.         char    newn[MAX_OSPATH];
  263.  
  264. //        Com_Printf ("100%%\n");
  265.  
  266.         fclose (cls.download);
  267.  
  268.         // rename the temp file to it's final name
  269.         CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
  270.         CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
  271.         r = rename (oldn, newn);
  272.         if (r)
  273.             Com_Printf ("failed to rename.\n");
  274.  
  275.         cls.download = NULL;
  276.         cls.downloadpercent = 0;
  277.  
  278.         // get another file if needed
  279.  
  280.         CL_RequestNextDownload ();
  281.     }
  282. }
  283.  
  284.  
  285. /*
  286. =====================================================================
  287.  
  288.   SERVER CONNECTING MESSAGES
  289.  
  290. =====================================================================
  291. */
  292.  
  293. /*
  294. ==================
  295. CL_ParseServerData
  296. ==================
  297. */
  298. void CL_ParseServerData (void)
  299. {
  300.     extern cvar_t    *fs_gamedirvar;
  301.     char    *str;
  302.     int        i;
  303.     
  304.     Com_DPrintf ("Serverdata packet received.\n");
  305. //
  306. // wipe the client_state_t struct
  307. //
  308.     CL_ClearState ();
  309.     cls.state = ca_connected;
  310.  
  311. // parse protocol version number
  312.     i = MSG_ReadLong (&net_message);
  313.     cls.serverProtocol = i;
  314.  
  315.     // BIG HACK to let demos from release work with the 3.0x patch!!!
  316.     if (Com_ServerState() && PROTOCOL_VERSION == 34)
  317.     {
  318.     }
  319.     else if (i != PROTOCOL_VERSION)
  320.         Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
  321.  
  322.     cl.servercount = MSG_ReadLong (&net_message);
  323.     cl.attractloop = MSG_ReadByte (&net_message);
  324.  
  325.     // game directory
  326.     str = MSG_ReadString (&net_message);
  327.     strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
  328.  
  329.     // set gamedir
  330.     if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
  331.         Cvar_Set("game", str);
  332.  
  333.     // parse player entity number
  334.     cl.playernum = MSG_ReadShort (&net_message);
  335.  
  336.     // get the full level name
  337.     str = MSG_ReadString (&net_message);
  338.  
  339.     if (cl.playernum == -1)
  340.     {    // playing a cinematic or showing a pic, not a level
  341.         SCR_PlayCinematic (str);
  342.     }
  343.     else
  344.     {
  345.         // seperate the printfs so the server message can have a color
  346.         Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
  347.         Com_Printf ("%c%s\n", 2, str);
  348.  
  349.         // need to prep refresh at next oportunity
  350.         cl.refresh_prepped = false;
  351.     }
  352. }
  353.  
  354. /*
  355. ==================
  356. CL_ParseBaseline
  357. ==================
  358. */
  359. void CL_ParseBaseline (void)
  360. {
  361.     entity_state_t    *es;
  362.     int                bits;
  363.     int                newnum;
  364.     entity_state_t    nullstate;
  365.  
  366.     memset (&nullstate, 0, sizeof(nullstate));
  367.  
  368.     newnum = CL_ParseEntityBits (&bits);
  369.     es = &cl_entities[newnum].baseline;
  370.     CL_ParseDelta (&nullstate, es, newnum, bits);
  371. }
  372.  
  373.  
  374. /*
  375. ================
  376. CL_LoadClientinfo
  377.  
  378. ================
  379. */
  380. void CL_LoadClientinfo (clientinfo_t *ci, char *s)
  381. {
  382.     int i;
  383.     char        *t;
  384.     char        model_name[MAX_QPATH];
  385.     char        skin_name[MAX_QPATH];
  386.     char        model_filename[MAX_QPATH];
  387.     char        skin_filename[MAX_QPATH];
  388.     char        weapon_filename[MAX_QPATH];
  389.  
  390.     strncpy(ci->cinfo, s, sizeof(ci->cinfo));
  391.     ci->cinfo[sizeof(ci->cinfo)-1] = 0;
  392.  
  393.     // isolate the player's name
  394.     strncpy(ci->name, s, sizeof(ci->name));
  395.     ci->name[sizeof(ci->name)-1] = 0;
  396.     t = strstr (s, "\\");
  397.     if (t)
  398.     {
  399.         ci->name[t-s] = 0;
  400.         s = t+1;
  401.     }
  402.  
  403.     if (cl_noskins->value || *s == 0)
  404.     {
  405.         Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
  406.         Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
  407.         Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
  408.         Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
  409.         ci->model = R_RegisterModel (model_filename);
  410.         memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
  411.         ci->weaponmodel[0] = R_RegisterModel (weapon_filename);
  412.         ci->skin = R_RegisterSkin (skin_filename);
  413.         ci->icon = R_RegisterPic (ci->iconname);
  414.     }
  415.     else
  416.     {
  417.         // isolate the model name
  418.         strcpy (model_name, s);
  419.         t = strstr(model_name, "/");
  420.         if (!t)
  421.             t = strstr(model_name, "\\");
  422.         if (!t)
  423.             t = model_name;
  424.         *t = 0;
  425.  
  426.         // isolate the skin name
  427.         strcpy (skin_name, s + strlen(model_name) + 1);
  428.  
  429.         // model file
  430.         Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
  431.         ci->model = R_RegisterModel (model_filename);
  432.         if (!ci->model)
  433.         {
  434.             strcpy(model_name, "male");
  435.             Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
  436.             ci->model = R_RegisterModel (model_filename);
  437.         }
  438.  
  439.         // skin file
  440.         Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
  441.         ci->skin = R_RegisterSkin (skin_filename);
  442.  
  443.         // if we don't have the skin and the model wasn't male,
  444.         // see if the male has it (this is for CTF's skins)
  445.          if (!ci->skin && Q_stricmp(model_name, "male"))
  446.         {
  447.             // change model to male
  448.             strcpy(model_name, "male");
  449.             Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
  450.             ci->model = R_RegisterModel (model_filename);
  451.  
  452.             // see if the skin exists for the male model
  453.             Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
  454.             ci->skin = R_RegisterSkin (skin_filename);
  455.         }
  456.  
  457.         // if we still don't have a skin, it means that the male model didn't have
  458.         // it, so default to grunt
  459.         if (!ci->skin) {
  460.             // see if the skin exists for the male model
  461.             Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
  462.             ci->skin = R_RegisterSkin (skin_filename);
  463.         }
  464.  
  465.         // weapon file
  466.         for (i = 0; i < num_cl_weaponmodels; i++) {
  467.             Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
  468.             ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
  469.             if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
  470.                 // try male
  471.                 Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
  472.                 ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
  473.             }
  474.             if (!cl_vwep->value)
  475.                 break; // only one when vwep is off
  476.         }
  477.  
  478.         // icon file
  479.         Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
  480.         ci->icon = R_RegisterPic (ci->iconname);
  481.     }
  482.  
  483.     // must have loaded all data types to be valud
  484.     if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
  485.     {
  486.         ci->skin = NULL;
  487.         ci->icon = NULL;
  488.         ci->model = NULL;
  489.         ci->weaponmodel[0] = NULL;
  490.         return;
  491.     }
  492. }
  493.  
  494. /*
  495. ================
  496. CL_ParseClientinfo
  497.  
  498. Load the skin, icon, and model for a client
  499. ================
  500. */
  501. void CL_ParseClientinfo (int player)
  502. {
  503.     char            *s;
  504.     clientinfo_t    *ci;
  505.  
  506.     s = cl.configstrings[player+CS_PLAYERSKINS];
  507.  
  508.     ci = &cl.clientinfo[player];
  509.  
  510.     CL_LoadClientinfo (ci, s);
  511. }
  512.  
  513.  
  514. /*
  515. ================
  516. CL_ParseConfigString
  517. ================
  518. */
  519. void CL_ParseConfigString (void)
  520. {
  521.     int        i;
  522.     char    *s;
  523.     char    olds[MAX_QPATH];
  524.  
  525.     i = MSG_ReadShort (&net_message);
  526.     if (i < 0 || i >= MAX_CONFIGSTRINGS)
  527.         Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
  528.     s = MSG_ReadString(&net_message);
  529.  
  530.     strncpy (olds, cl.configstrings[i], sizeof(olds));
  531.     olds[sizeof(olds) - 1] = 0;
  532.  
  533.     strcpy (cl.configstrings[i], s);
  534.  
  535.     // do something apropriate 
  536.  
  537.     if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
  538.         CL_SetLightstyle (i - CS_LIGHTS);
  539.     else if (i == CS_CDTRACK)
  540.     {
  541.         if (cl.refresh_prepped)
  542.             CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
  543.     }
  544.     else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
  545.     {
  546.         if (cl.refresh_prepped)
  547.         {
  548.             cl.model_draw[i-CS_MODELS] = R_RegisterModel (cl.configstrings[i]);
  549.             if (cl.configstrings[i][0] == '*')
  550.                 cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
  551.             else
  552.                 cl.model_clip[i-CS_MODELS] = NULL;
  553.         }
  554.     }
  555.     else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
  556.     {
  557.         if (cl.refresh_prepped)
  558.             cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
  559.     }
  560.     else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
  561.     {
  562.         if (cl.refresh_prepped)
  563.             cl.image_precache[i-CS_IMAGES] = R_RegisterPic (cl.configstrings[i]);
  564.     }
  565.     else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
  566.     {
  567.         if (cl.refresh_prepped && strcmp(olds, s))
  568.             CL_ParseClientinfo (i-CS_PLAYERSKINS);
  569.     }
  570. }
  571.  
  572.  
  573. /*
  574. =====================================================================
  575.  
  576. ACTION MESSAGES
  577.  
  578. =====================================================================
  579. */
  580.  
  581. /*
  582. ==================
  583. CL_ParseStartSoundPacket
  584. ==================
  585. */
  586. void CL_ParseStartSoundPacket(void)
  587. {
  588.     vec3_t  pos_v;
  589.     float    *pos;
  590.     int     channel, ent;
  591.     int     sound_num;
  592.     float     volume;
  593.     float     attenuation;  
  594.     int        flags;
  595.     float    ofs;
  596.  
  597.     flags = MSG_ReadByte (&net_message);
  598.     sound_num = MSG_ReadByte (&net_message);
  599.  
  600.     if (flags & SND_VOLUME)
  601.         volume = MSG_ReadByte (&net_message) / 255.0;
  602.     else
  603.         volume = DEFAULT_SOUND_PACKET_VOLUME;
  604.     
  605.     if (flags & SND_ATTENUATION)
  606.         attenuation = MSG_ReadByte (&net_message) / 64.0;
  607.     else
  608.         attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;    
  609.  
  610.     if (flags & SND_OFFSET)
  611.         ofs = MSG_ReadByte (&net_message) / 1000.0;
  612.     else
  613.         ofs = 0;
  614.  
  615.     if (flags & SND_ENT)
  616.     {    // entity reletive
  617.         channel = MSG_ReadShort(&net_message); 
  618.         ent = channel>>3;
  619.         if (ent > MAX_EDICTS)
  620.             Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
  621.  
  622.         channel &= 7;
  623.     }
  624.     else
  625.     {
  626.         ent = 0;
  627.         channel = 0;
  628.     }
  629.  
  630.     if (flags & SND_POS)
  631.     {    // positioned in space
  632.         MSG_ReadPos (&net_message, pos_v);
  633.  
  634.         pos = pos_v;
  635.     }
  636.     else    // use entity number
  637.         pos = NULL;
  638.  
  639.     if (!cl.sound_precache[sound_num])
  640.         return;
  641.  
  642.     S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
  643. }       
  644.  
  645.  
  646. void SHOWNET(char *s)
  647. {
  648.     if (cl_shownet->value>=2)
  649.         Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
  650. }
  651.  
  652. /*
  653. =====================
  654. CL_ParseServerMessage
  655. =====================
  656. */
  657. void CL_ParseServerMessage (void)
  658. {
  659.     int            cmd;
  660.     char        *s;
  661.     int            i;
  662.  
  663. //
  664. // if recording demos, copy the message out
  665. //
  666.     if (cl_shownet->value == 1)
  667.         Com_Printf ("%i ",net_message.cursize);
  668.     else if (cl_shownet->value >= 2)
  669.         Com_Printf ("------------------\n");
  670.  
  671.  
  672. //
  673. // parse the message
  674. //
  675.     while (1)
  676.     {
  677.         if (net_message.readcount > net_message.cursize)
  678.         {
  679.             Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
  680.             break;
  681.         }
  682.  
  683.         cmd = MSG_ReadByte (&net_message);
  684.  
  685.         if (cmd == -1)
  686.         {
  687.             SHOWNET("END OF MESSAGE");
  688.             break;
  689.         }
  690.  
  691.         if (cl_shownet->value>=2)
  692.         {
  693.             if (!svc_strings[cmd])
  694.                 Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
  695.             else
  696.                 SHOWNET(svc_strings[cmd]);
  697.         }
  698.     
  699.     // other commands
  700.         switch (cmd)
  701.         {
  702.         default:
  703.             Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
  704.             break;
  705.             
  706.         case svc_nop:
  707. //            Com_Printf ("svc_nop\n");
  708.             break;
  709.             
  710.         case svc_disconnect:
  711.             Com_Error (ERR_DISCONNECT,"Server disconnected\n");
  712.             break;
  713.  
  714.         case svc_reconnect:
  715.             Com_Printf ("Server disconnected, reconnecting\n");
  716.             if (cls.download) {
  717.                 //ZOID, close download
  718.                 fclose (cls.download);
  719.                 cls.download = NULL;
  720.             }
  721.             cls.state = ca_connecting;
  722.             cls.connect_time = -99999;    // CL_CheckForResend() will fire immediately
  723.             break;
  724.  
  725.         case svc_print:
  726.             i = MSG_ReadByte (&net_message);
  727.             if (i == PRINT_CHAT)
  728.             {
  729.                 S_StartLocalSound ("misc/talk.wav");
  730.                 con.ormask = 128;
  731.             }
  732.             Com_Printf ("%s", MSG_ReadString (&net_message));
  733.             con.ormask = 0;
  734.             break;
  735.             
  736.         case svc_centerprint:
  737.             SCR_CenterPrint (MSG_ReadString (&net_message));
  738.             break;
  739.             
  740.         case svc_stufftext:
  741.             s = MSG_ReadString (&net_message);
  742.             Com_DPrintf ("stufftext: %s\n", s);
  743.             Cbuf_AddText (s);
  744.             break;
  745.             
  746.         case svc_serverdata:
  747.             Cbuf_Execute ();        // make sure any stuffed commands are done
  748.             CL_ParseServerData ();
  749.             break;
  750.             
  751.         case svc_configstring:
  752.             CL_ParseConfigString ();
  753.             break;
  754.             
  755.         case svc_sound:
  756.             CL_ParseStartSoundPacket();
  757.             break;
  758.             
  759.         case svc_spawnbaseline:
  760.             CL_ParseBaseline ();
  761.             break;
  762.  
  763.         case svc_temp_entity:
  764.             CL_ParseTEnt ();
  765.             break;
  766.  
  767.         case svc_muzzleflash:
  768.             CL_ParseMuzzleFlash ();
  769.             break;
  770.  
  771.         case svc_muzzleflash2:
  772.             CL_ParseMuzzleFlash2 ();
  773.             break;
  774.  
  775.         case svc_download:
  776.             CL_ParseDownload ();
  777.             break;
  778.  
  779.         case svc_frame:
  780.             CL_ParseFrame ();
  781.             break;
  782.  
  783.         case svc_inventory:
  784.             CL_ParseInventory ();
  785.             break;
  786.  
  787.         case svc_layout:
  788.             s = MSG_ReadString (&net_message);
  789.             strncpy (cl.layout, s, sizeof(cl.layout)-1);
  790.             break;
  791.  
  792.         case svc_playerinfo:
  793.         case svc_packetentities:
  794.         case svc_deltapacketentities:
  795.             Com_Error (ERR_DROP, "Out of place frame data");
  796.             break;
  797.         }
  798.     }
  799.  
  800.     CL_AddNetgraph ();
  801.  
  802.     //
  803.     // we don't know if it is ok to save a demo message until
  804.     // after we have parsed the frame
  805.     //
  806.     if (cls.demorecording && !cls.demowaiting)
  807.         CL_WriteDemoMessage ();
  808.  
  809. }
  810.  
  811.  
  812.